package com.weilele.mvvm

import android.app.Activity
import android.app.Application
import android.content.Intent
import android.os.Handler
import android.os.Looper
import android.util.Log
import androidx.lifecycle.ProcessLifecycleOwner
import com.google.gson.Gson
import com.orhanobut.logger.AndroidLogAdapter
import com.orhanobut.logger.Logger
import com.orhanobut.logger.PrettyFormatStrategy
import com.weilele.mvvm.base.MvvmActivity
import com.weilele.mvvm.utils.MvvmActivityLifecycleCallbacks
import com.weilele.mvvm.utils.MvvmActivityLifecycleCallbacks.Companion._activityList
import com.weilele.mvvm.utils.`object`.CrashHelper
import com.weilele.mvvm.utils.`object`.ScreenAdaptationObj
import com.weilele.mvvm.utils.local.AppBackgroundRun
import com.weilele.mvvm.utils.logI
import com.weilele.mvvm.utils.net.OkHttpCertUtils
import okhttp3.FormBody
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import okhttp3.Response
import okhttp3.internal.readBomAsCharset
import java.util.concurrent.TimeUnit
import java.util.zip.GZIPInputStream
import kotlin.text.Charsets.UTF_8

//---------------------------------------------初始化mvvm库--------------------------------------
/**
 * gson
 */
val gson by lazy { Gson() }

/**
 * 主线程的handle
 */
val mainHandler by lazy { Handler(Looper.getMainLooper()) }

/**
 * 给外部调用创建okHttp设置参数的回调
 */
private var clientCall: ((OkHttpClient.Builder) -> Unit)? = null

/**
 * 当前app的包名
 */
val packageName by lazy { app.packageName }

/**
 * okHttp构建器
 */
val okHttpClientBuilder: OkHttpClient.Builder by lazy {
    OkHttpCertUtils.createCertOkHttpBuilder().apply {
        connectTimeout(3, TimeUnit.MINUTES)
        readTimeout(3, TimeUnit.MINUTES)
        writeTimeout(3, TimeUnit.MINUTES)
        if (MvvmConf.isDebug && LibraryConf.enableLoggerLibrary) {//debug模式
            //需要注意两种拦截器的区别
            addNetworkInterceptor {
                httpRequestLog(it)
            }
        }
    }
}

/**
 * okHttp对象
 */
val okHttpClient: OkHttpClient by lazy {
    clientCall?.invoke(okHttpClientBuilder)
    okHttpClientBuilder.build()
}

/**
 * 全局的application对象
 */
lateinit var app: Application


val activityList: List<Activity>
    get() = _activityList

/**
 * 设置创建全局OkHttpClient的监听
 */
fun setMvvmLibOnCreateOkHttpListener(call: ((OkHttpClient.Builder) -> Unit)) {
    clientCall = call
}

/**
 * [com.weilele.mvvm.MvvmConf]应该在此方法之前设置
 */
internal fun initMvvmLib(application: Application) {
    application.logI { "---------------mvvm库初始化完毕-----------------------" }
    app = application
    //日志打印
    initLog()
    //监听程序生命周期
    ProcessLifecycleOwner.get().lifecycle.addObserver(AppBackgroundRun)
    application.registerActivityLifecycleCallbacks(MvvmActivityLifecycleCallbacks())
    if (MvvmConf.enableUncaughtExceptionHandler) {
        Thread.setDefaultUncaughtExceptionHandler(CrashHelper)
    }
}

//是否开启屏幕适配,支持所有activity，字体过大可以调整缩放因子
fun setScreenAdaptation(activity: Activity) {
    //是否开启第三方库的屏幕适配
    ScreenAdaptationObj.setCustomDensity(
        activity,
        MvvmConf.enableScreenAdaptation
                && MvvmConf.enableOtherLibraryScreenAdaptation
                && activity !is MvvmActivity
    )
}


/**
 * 初始化日志
 */
private fun initLog() {
    //不是debug模式不初始化
    if (!MvvmConf.isDebug) {
        return
    }
    if (!LibraryConf.enableLoggerLibrary) {
        return
    }
    //日志打印
    val formatStrategy = PrettyFormatStrategy.newBuilder()
        .showThreadInfo(false)  // (Optional) Whether to show thread info or not. Default true
        .methodCount(0)         // (Optional) How many method line to show. Default 2
        .methodOffset(7)        // (Optional) Hides internal method calls up to offset. Default 5
//            .logStrategy(customLog) // (Optional) Changes the log strategy to print out. Default LogCat
        .tag("--->")   // (Optional) Global tag for every log. Default PRETTY_LOGGER
        .build()
    Logger.addLogAdapter(AndroidLogAdapter(formatStrategy))
}

/**
 * 打印Http请求日志
 */
private fun httpRequestLog(chain: Interceptor.Chain): Response {
    val request = chain.request()
    val bodyStr = StringBuilder()
    val requestParams = when (val body = request.body) {
        is FormBody -> {
            repeat(body.size) {
                bodyStr.append(body.encodedName(it))
                bodyStr.append(":")
                bodyStr.append(body.encodedValue(it))
                bodyStr.append(",")
            }
            bodyStr.toString()
        }
        else -> {
            bodyStr.append(body.toString())
            bodyStr.append("\n不是FormBody，不支持打印请求参数").toString()
        }
    }
    val requestLog = "发送请求：${request.url}\n请求参数：${requestParams}\n请求头:\n${request.headers}"
    if (LibraryConf.enableLoggerLibrary) {
        Logger.i(requestLog)
    } else {
        Log.i("网络请求日志拦截", "--------------------------------------------------------")
        Log.i("网络请求日志拦截", requestLog)
    }
    val startTime = System.nanoTime()
    val response = chain.proceed(request)
    val endTime = System.nanoTime()
    val oldSource = response.body?.source() ?: return response
    oldSource.request(java.lang.Long.MAX_VALUE)
    val buffer = oldSource.buffer.clone()
    val charset =
        buffer.readBomAsCharset(response.body?.contentType()?.charset(UTF_8) ?: UTF_8)
    val responseStr = if (
        response.header("Content-Encoding")?.contains("gzip", true) == true ||
        response.header("Accept-Encoding")?.contains("gzip", true) == true
    ) {
        GZIPInputStream(buffer.inputStream()).bufferedReader(charset).readText()
    } else {
        buffer.inputStream().bufferedReader(charset).readText()
    }
    val responseLog = "{\'响应链接\':\'${response.request.url}\'," +
            "\'响应请求头\':\'${response.headers}\'," +
            "\'响应时间\':\'${(endTime - startTime) / 1e6} ms\'," +
            "\'响应数据\':${responseStr}}"
    if (LibraryConf.enableLoggerLibrary) {
        if ((responseStr.startsWith('{') || responseStr.startsWith('['))
            && (responseStr.endsWith('}') || responseStr.endsWith(']'))
        ) {
            Logger.json(responseLog)
        } else {
            Logger.i(responseLog)
        }
    } else {
        Log.i("网络请求日志拦截", responseLog)
        Log.i("网络请求日志拦截", "--------------------------------------------------------")
    }
    return response
}


